import pathlib
from django.http import HttpResponse, JsonResponse,FileResponse
from mxDemo2.settings import BASE_DIR, BASE_URL
import os
from web import models
from datetime import datetime
import time
from django.shortcuts import get_object_or_404
from django.core.exceptions import PermissionDenied
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
from django.views.decorators.http import require_http_methods
from django.utils import timezone
from django.db.models import Min, Max
import base64


# 公共函数：获取当前时间
def get_current_time():
    return format_time(timezone.now())


# 公共函数:创建一个函数用于保存文件
def saveFile(file, file_name):
    # 获取文件路径的目录部分
    directory = os.path.dirname(file_name)

    # 如果目录不存在，则创建它（包括所有必要的父目录）
    if not os.path.exists(directory):
        os.makedirs(directory)

    # 以二进制写入模式打开文件，并写入文件块
    with open(file_name, 'wb+') as destination:
        for chunk in file.chunks():
            destination.write(chunk)


# 公共函数:读取上传的文件内容，并返回
def readFile(filename) -> str:
    # 以二进制读取模式打开文件，并读取内容
    try:
        with open(filename, 'rb') as f:
            content = f.read()
            base64_content = base64.b64encode(content).decode('utf-8')
        return base64_content
    except FileNotFoundError:
        return "File not found"
    except OSError as e:
        # 捕获其他可能的文件I/O错误
        return f"An error occurred: {e}"


# 公共函数：存放路径拼接
def get_store_path(url):
    # 拼接文件的完整路径
    path_name = os.path.join(BASE_DIR, 'web', 'static', url)
    path = pathlib.Path(path_name)
    return path


# 公共函数：访问路径拼接
def get_visit_path(url):
    path = os.path.join(BASE_URL, url)
    return path


# 公共函数：时间格式化
def format_time(time):
    # 如果 time 是 datetime 对象，直接格式化
    if isinstance(time, datetime):
        return time.strftime('%Y-%m-%d %H:%M:%S')

        # 假设 time 是字符串，根据格式进行解析
    if '/' in time:
        # 处理包含'/'的日期时间格式，并替换为'-'
        time = time.replace('/', '-')
        try:
            # 尝试先解析包含秒的格式
            time_object = datetime.strptime(time, "%Y-%m-%d %H:%M:%S")
        except ValueError:
            try:
                # 如果解析失败，则尝试不包含秒的格式
                time_object = datetime.strptime(time, "%Y-%m-%d %H:%M")
                # 如果没有秒，则此时已经成功解析，无需额外操作
            except ValueError:
                # 如果还是解析失败，则抛出异常
                raise ValueError(f"Cannot parse time: {time}")
    elif 'T' in time and 'Z' in time:
        # 处理ISO 8601格式的时间字符串
        time = time.replace('T', ' ').replace('Z', '')
        try:
            # 尝试先解析包含秒的格式
            time_object = datetime.strptime(time, "%Y-%m-%d %H:%M:%S")
        except ValueError:
            try:
                # 如果解析失败，则尝试不包含秒的格式
                time_object = datetime.strptime(time, "%Y-%m-%d %H:%M")
                # 如果没有秒，则此时已经成功解析，无需额外操作
            except ValueError:
                # 如果还是解析失败，则抛出异常
                raise ValueError(f"Cannot parse time: {time}")
    else:
        try:
            # 尝试先解析包含秒的格式
            time_object = datetime.strptime(time, "%Y-%m-%d %H:%M:%S")
        except ValueError:
            try:
                # 如果解析失败，则尝试不包含秒的格式
                time_object = datetime.strptime(time, "%Y-%m-%d %H:%M")
                # 如果没有秒，则此时已经成功解析，无需额外操作
            except ValueError:
                # 如果还是解析失败，则抛出异常
                raise ValueError(f"Cannot parse time: {time}")
        # 返回格式化后的时间字符串
        return time_object.strftime('%Y-%m-%d %H:%M:%S')

# 公共函数：时间化为时间戳
def timestamp(date_string, date_format="%Y-%m-%d %H:%M:%S"):
    """
    将给定的日期时间字符串转换为时间戳。

    参数:
    - date_string: 字符串，表示日期时间。
    - date_format: 字符串，定义日期时间字符串的格式，默认为"%Y/%m/%d %H:%M:%S"。

    返回:
    - 时间戳，表示自1970年1月1日00:00:00（UTC）以来的秒数。
    """
    # 使用strptime函数将字符串转换为datetime对象
    date_object = datetime.strptime(date_string, date_format)

    # 将datetime对象转换为时间戳
    timestamp = time.mktime(date_object.timetuple())

    return timestamp

# 公共函数：格式化数据列表
def format_data(data):
    # 遍历查询结果并格式化
    formatted_data = []
    for item in data:
        img = get_visit_path(item.img) if hasattr(item, 'img') and item.img else None
        formatted_item = {
            'id': item.id,
            'title': item.title,
            'time': format_time(item.time) if item.time else None,
            'url': item.url if hasattr(item, 'img') else get_visit_path(item.url),
            'author': item.author,
        }
        if img is not None:
            formatted_item['img'] = img+f'?{timestamp(get_current_time())}'

        formatted_data.append(formatted_item)
    return formatted_data


# 公共函数: 用于新建数据时初始化id
def get_id(model):
    # 获取最新的id并加1，用于新数据的id
    id = 1
    try:
        if model.objects.order_by('-id').first():
            id = model.objects.order_by('-id').first().id + 1
    except Exception as e:
        print(f"Error in get_id: {e}")
    return id


# 分页函数
def limit(qs, page, pagesize):
    """
    对给定的查询集进行分页处理。

    参数:
    - qs (queryset): 需要分页的查询集。
    - page (int): 当前页码（从1开始）。
    - pagesize (int): 每页显示的条目数。

    返回:
    - dict: 包含分页信息的字典。
        {
            "pages": total_pages,  # 总页数
            "list": paginated_list,  # 当前页的条目列表
            "page": page,  # 当前页码
            "pagesize": pagesize  # 每页条目数
        }
    """
    # 计算当前页的查询集切片
    l = qs[(page - 1) * pagesize: page * pagesize]

    # 计算查询集的总条目数
    total = len(qs)

    # 计算总页数
    if total % pagesize > 0:
        pages = total // pagesize + 1  # 如果有余数，增加一页
    else:
        pages = total // pagesize  # 没有余数，页数刚好

    # 返回包含分页信息的字典
    return {
        "pages": pages,
        "list": l,
        "page": page,
        "pagesize": pagesize,
        "total": total
    }


# 主页展示
def index(request):
    # 格式化数据为指定结构的函数
    try:
        # 获取企业动态、通知公文、规章制度的数据并格式化
        data1 = models.dynamic.objects.all().order_by('-time')[:4]
        formatted_data = format_data(data1)

        data2 = models.inform.objects.all().order_by('-time')[:5]
        formatted_data2 = format_data(data2)

        data3 = models.system.objects.all().order_by('-time')[:5]
        formatted_data3 = format_data(data3)
        return JsonResponse(
            {'code': 200, 'data': {'dynamic': formatted_data, 'inform': formatted_data2, 'system': formatted_data3}})
    except Exception as e:
        return JsonResponse({'code': 400, 'message': str(e), }, status=400)


# 通用的展示数据函数
def display_data(request, model_name):
    # 默认页码为1，每页二十条数据
    page = int(request.GET.get('page')) if request.GET.get('page') else 1
    pagesize = int(request.GET.get('pagesize')) if request.GET.get('pagesize') else 10
    try:
        # 尝试获取指定模型的全部数据
        query = model_name.objects.all().order_by('-time')
        time_start = request.GET.get('time_start') if request.GET.get('time_start') else query.aggregate(Min('time'))[
            'time__min']
        time_end = request.GET.get('time_end') if request.GET.get('time_end') else query.aggregate(Max('time'))[
            'time__max']
        if time_start and time_end:
            start_date = format_time(time_start)  # 根据你的时间格式调整
            end_date = format_time(time_end)  # 根据你的时间格式调整
            query = query.filter(time__range=(start_date, end_date))
    except Exception as e:
        # 数据库查询出现问题，返回错误信息
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)

    # 遍历查询结果并格式化
    formatted_data = format_data(query)
    # 返回经过格式化的数据
    return JsonResponse({'code': 200, 'data': limit(formatted_data, page, pagesize)})


# 企业动态展示
def dynamic(request):
    # 使用通用展示函数展示企业动态
    return display_data(request, models.dynamic)


# 通知公文展示
def inform(request):
    # 使用通用展示函数展示通知公文
    return display_data(request, models.inform)


# 规章制度展示
def system(request):
    # 使用通用展示函数展示规章制度
    return display_data(request, models.system)


def get_object_info(request, model):
    # 获取对象的id并查询具体内容
    id = request.GET.get('id')
    if not id or not id.isdigit():
        return JsonResponse({'code': 400, 'message': '无效的ID'}, status=400)
    try:
        obj = model.objects.filter(id=id).first()
        if obj:
            data = {
                'id': obj.id,
                'url': obj.url if hasattr(obj, 'img') else str(get_visit_path(obj.url)),
                'title': obj.title,
                'time': format_time(obj.time)
            }
            if model == models.dynamic:
                data['img'] = get_visit_path(obj.img) if hasattr(obj, 'img') else None,
            else:
                data['pdf_b'] = readFile(get_store_path(obj.url))

            return JsonResponse({'code': 200, 'data': data})
        else:
            return JsonResponse({'code': 400, 'message': '未查询到数据'}, status=400)
    except Exception as e:
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)


# 通知公文具体内容
def inform_info(request):
    return get_object_info(request, models.inform)


# 企业动态具体内容
def dynamic_info(request):
    return get_object_info(request, models.dynamic)


# 规章制度具体内容
def system_info(request):
    return get_object_info(request, models.system)


# 后台内容展示
# def backend(request):
#     page = int(request.GET.get('page')) if request.GET.get('page') else 1
#     pagesize = int(request.GET.get('pagesize'))
#     if not page or not pagesize:
#         return JsonResponse({'code': 400, 'message': ' page / pagesize 为空'}, status=400)
#     try:
#         # 获取企业动态、通知公文、规章制度的数据并格式化
#         data1 = models.dynamic.objects.all().order_by('-time')
#         data2 = models.inform.objects.all().order_by('-time')
#         data3 = models.system.objects.all().order_by('-time')
#
#         formatted_data1 = format_data(data1)
#         formatted_data2 = format_data(data2)
#         formatted_data3 = format_data(data3)
#
#         # 渲染后台管理页面
#         return JsonResponse(
#             {'code': 200, 'data': {'dynamic': formatted_data1, 'inform': formatted_data2, 'system': formatted_data3}})
#     except Exception as e:
#         return JsonResponse({'code': 400, 'message': str(e)}, status=400)


# 企业动态添加
# 使用装饰器来确保只接受 POST 请求
@require_http_methods(["POST"])
def dynamic_add(request):
    # 获取用于命名的id
    id = get_id(models.dynamic)
    # 获取表单内容
    title = request.POST.get('title')
    time = get_current_time()  # 获取本地时间
    url = request.POST.get('url')
    img_file = request.FILES.get('img_file')
    author = request.POST.get('author')
    # 检查必填项是否齐全
    if not all([title, author, url, img_file]):
        return JsonResponse({'code': 400, 'message': 'title, author,img_file 和 url 不能为空'}, status=400)

    # 检查文件类型 (对于图片)
    if img_file:
        valid_image_types = ['image/jpeg', 'image/png', 'image/gif']
        if img_file.content_type not in valid_image_types:
            return JsonResponse(
                {'code': 400, 'message': "Invalid file type. Only JPEG, PNG, and GIF images are allowed."}, status=400)
    # 添加数据到数据库
    try:
        models.dynamic.objects.create(id=id, img=f'in/img/dynamic_img_{id}.jpg', url=url, time=time, title=title,
                                      author=author)
        # 定义图片存储路径
        img_file_name = os.path.join(BASE_DIR, 'web', 'static', 'in', 'img', f'dynamic_img_{id}.jpg')
        # 保存图片文件
        saveFile(img_file, img_file_name)
        return JsonResponse({'code': 200, 'message': '添加成功'})
    except Exception as e:
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)


# 通知公文添加
# 使用装饰器来确保只接受 POST 请求
@require_http_methods(["POST"])
def inform_add(request):
    # 获取用于命名的id
    id = get_id(models.inform)
    # 获取表单内容
    title = request.POST.get('title')
    time = get_current_time()
    pdf_file = request.FILES.get('pdf_file')
    author = request.POST.get('author', )
    # 检查必填项是否齐全
    if not all([title, author, pdf_file]):
        return JsonResponse({'code': 400, 'message': 'title, author,pdf_file不能为空'}, status=400)
    # 检查文件类型 (对于PDF)
    if pdf_file and pdf_file.content_type != 'application/pdf':
        return JsonResponse({'code': 400, 'message': 'sInvalid file type. Only PDF file are allowed.'}, status=400)
    pdf_file_name = os.path.join(BASE_DIR, 'web', 'static', 'in', 'pdf', f'inform_pdf_{id}.pdf')
    # 添加数据到数据库
    try:
        models.inform.objects.create(id=id, url=f'in/pdf/inform_pdf_{id}.pdf', time=time, title=title, author=author)
        # 保存PDF文件
        saveFile(pdf_file, pdf_file_name)
        return JsonResponse({'code': 200, 'message': '添加成功'})
    except Exception as e:
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)


# 规章制度添加
# 使用装饰器来确保只接受 POST 请求
@require_http_methods(["POST"])
def system_add(request):
    # 获取用于命名的id
    id = get_id(models.system)
    # 获取表单内容
    title = request.POST.get('title')
    author = request.POST.get('author', '')
    time = get_current_time()
    pdf_file = request.FILES.get('pdf_file')
    # 检查必填项是否齐全
    if not all([title, author, pdf_file]):
        return JsonResponse({'code': 400, 'message': 'title, author,pdf_file不能为空'}, status=400)
    # 检查文件类型 (对于PDF)
    if pdf_file and pdf_file.content_type != 'application/pdf':
        return JsonResponse({'code': 400, 'message': "Invalid file type. Only PDF files are allowed."}, status=400)
    pdf_file_name = os.path.join(BASE_DIR, 'web', 'static', 'in', 'pdf', f'system_pdf_{id}.pdf')

    # 添加数据到数据库
    try:
        models.system.objects.create(id=id, url=f'in/pdf/system_pdf_{id}.pdf', time=time, title=title, author=author)
        # 保存PDF文件
        saveFile(pdf_file, pdf_file_name)
        return JsonResponse({'code': 200, 'message': '添加成功'})
    except Exception as e:
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)


# 使用装饰器来确保只接受 POST 请求
@require_http_methods(["POST"])
def delete_item(request, model_cls):
    # 获取要删除的记录的id
    id = request.POST.get('id')
    if not id or not id.isdigit():
        return JsonResponse({'code': 400, 'message': '无效的ID'}, status=400)
    try:
        # 获取记录
        item = model_cls.objects.get(id=int(id))
        # 检查权限（这里只是一个示例,需要根据需求来实现）
        # if not request.user.has_perm('myapp.delete_' + model_cls._meta.model_name):
        #     raise PermissionDenied("你没有权限删除这个对象")

        # 获取文件路径
        file_path = get_store_path(getattr(item, 'img' if model_cls == models.dynamic else 'url', None))
        # 删除文件（如果存在）
        if file_path and file_path.exists():
            file_path.unlink()

        # 删除数据库记录
        item.delete()
        return JsonResponse({'code': 200, 'message': '删除成功'})
    except model_cls.DoesNotExist:
        # 记录不存在
        return JsonResponse({'code': 400, 'message': '未查询到数据'}, status=400)
    except Exception as e:
        # 其他异常
        return JsonResponse({'code': 400, 'message': str(e)}, status=400)

    # 企业动态删除


def dynamic_del(request):
    return delete_item(request, models.dynamic)


# 通知公文删除
def inform_del(request):
    return delete_item(request, models.inform)


# 规章制度删除
def system_del(request):
    return delete_item(request, models.system)


def file_update(file_path, file, Model, id, update_fields):
    try:
        if file:
            print(file_path.exists())
            # 删除旧文件（如果存在）
            if file_path.exists() and file_path.is_file():
                file_path.unlink()

            # 保存新文件
            saveFile(file, file_path)

            # 更新数据库记录
        # 注意：如果 update_fields 为空或包含非字段名，这将会导致错误
        # 确保 update_fields 是一个有效的字典
        Model.objects.filter(id=id).update(**update_fields)
        # 返回成功响应
        return JsonResponse({'code': 200, 'message': '文件更新成功'})

    except FileNotFoundError:
        # 如果文件不存在，返回一个错误响应
        return JsonResponse({'code': 400, 'message': '旧文件不存在'}, status=400)

    except OSError as e:
        # 捕获文件系统错误（例如，权限问题）
        return JsonResponse({'code': 400, 'message': '文件系统错误: {}'.format(str(e))}, status=400)

    except Exception as e:
        # 捕获其他所有异常
        return JsonResponse({'code': 400, 'message': '内部服务器错误: {}'.format(str(e))}, status=400)

    # 注意：这个函数应该被调用在 Django 视图函数中，并且确保传入的参数是有效的


# 通用编辑函数
# 使用装饰器来确保只接受 POST 请求
@require_http_methods(["POST"])
def edit(request, model):
    # 获取要编辑的记录的id
    id = request.POST.get('id')
    if not id or not id.isdigit():
        return JsonResponse({'code': 400, 'message': '无效的ID'}, status=400)
    obj = model.objects.filter(id=id).first()
    if not obj:
        return JsonResponse({'code': 400, 'message': '数据不存在'}, status=400)
    try:
        if request.method == 'POST':
            # 处理表单提交
            title = request.POST.get('title', '') or obj.title
            time_str = request.POST.get('time', '') or obj.time
            author = request.POST.get('author', '') or obj.author
            try:
                time = format_time(time_str) if time_str else None
            except ValueError:
                # 解析失败时处理异常
                print("无法解析时间格式")
                time = None  # 或者你可以根据需求选择其他处理方式
                return JsonResponse({'code': 400, 'message': '无法解析时间格式'}, status=400)

            formatted_item = {
                'title': title,
                'time': time,
                'author': author
            }
            if model == models.dynamic:
                url = request.POST.get('url', '') or obj.url
                # 处理企业动态特有的图片文件
                formatted_item['url'] = url
                img = obj.img
                img_file = request.FILES.get('img_file')
                # 检查文件类型 (对于图片)
                if img_file and img_file.content_type not in ['image/jpeg', 'image/png', 'image/gif']:
                    return JsonResponse(
                        {'code': 400, 'message': "Invalid file type. Only JPEG, PNG, and GIF images are allowed."},
                        status=400)
                file_path = get_store_path(img)
                return file_update(file_path, img_file, model, id, formatted_item)
            else:
                url = obj.url
                # 处理通知公文和规章制度特有的PDF文件
                pdf_file = request.FILES.get('pdf_file')
                # 检查文件类型 (对于PDF)
                if pdf_file and pdf_file.content_type != 'application/pdf':
                    return JsonResponse({'code': 400, 'message': "Invalid file type. Only PDF files are allowed."},
                                        status=400)
                file_path = get_store_path(url)
                return file_update(file_path, pdf_file, model, id, formatted_item)
    except model.DoesNotExist:
        # 记录不存在
        return JsonResponse({'code': 400, 'message': '未查询到数据'}, status=400)


# 企业动态修改
def dynamic_edit(request):
    return edit(request, models.dynamic)


# 通知公文修改
def inform_edit(request):
    return edit(request, models.inform)


# 规章制度修改
def system_edit(request):
    return edit(request, models.system)
